package online.inote.graphql.common.base;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.ibatis.session.RowBounds;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import tk.mybatis.mapper.entity.Example;

/**
 * @description: 基础Service
 * @author XQF.Sui
 * @created 2019年4月11日 下午9:53:06
 * @version 1.0
 */
public class BaseService<T extends IdEntity<ID>, ID> extends GenericService<T> {

	@Autowired
	protected BaseMapper<T> mapper;

	/**
	 * @description 根据对象属性查询
	 * @author XQF.Sui
	 * @created 2019年4月11日 下午9:54:51
	 * @param record
	 * @return
	 */
	public List<T> select(T record) {
		return mapper.select(record);
	}
	
	/**
	 * @description 查询所有数据(慎用)
	 * @author XQF.Sui
	 * @created 2019年4月11日 下午9:55:11
	 * @return
	 */
	public List<T> selectAll() {
		return mapper.selectAll();
	}
	
	/**
	 * @description 根据Example查询
	 * @author XQF.Sui
	 * @created 2019年4月11日 下午9:55:44
	 * @param example
	 * @return
	 */
	public List<T> selectByExample(Example example) {
		return mapper.selectByExample(example);
	}
	
	/**
	 * @description 根据Example查询单条记录
	 * @author XQF.Sui
	 * @created 2019年4月18日 下午9:24:54
	 * @param example
	 * @param handle
	 * @return
	 */
	public T selectByExample(Example example, MultipleResultsHandle handle) {
		
		if (!MultipleResultsHandle.contains(handle))
			throw new RuntimeException("未知的处理方式");
		
		List<T> list = this.selectByExample(example);
		
		if (CollectionUtils.isEmpty(list)) {
			return null;
		} else if (list.size() > 1) {
			if (MultipleResultsHandle.IGNORE.equals(handle)) {
				return list.get(0);
			} else if (MultipleResultsHandle.EXCEPTION.equals(handle)) {
				throw new RuntimeException("查询单条数据时, 返回多条数据！class:[ " + clazz + " ]");
			}
		}
		
		return null;
	}
	
	/**
	 * @description 根据实体对象属性查询所有符合条件数据
	 * @author XQF.Sui
	 * @created 2019年4月11日 下午9:56:07
	 * @param property
	 * @param value
	 * @return
	 */
	public List<T> selectListByPropertyEqualTo(String property, Object value) {
		Example example = new Example(clazz);
		example.createCriteria().andEqualTo(property, value);
		
		return mapper.selectByExample(example);
	}
	
	/**
	 * @description 根据实体对象属性查询一条符合条件数据
	 * @author XQF.Sui
	 * @created 2019年4月11日 下午9:56:33
	 * @param property
	 * @param value
	 * @param handle
	 * @return
	 */
	public T selectByPropertyEqualTo(String property, Object value, MultipleResultsHandle handle) {
		
		if (!MultipleResultsHandle.contains(handle))
			throw new RuntimeException("未知的处理方式");
		
		List<T> list = this.selectListByPropertyEqualTo(property, value);
		
		if (CollectionUtils.isEmpty(list)) {
			return null;
		} else if (list.size() > 1) {
			if (MultipleResultsHandle.IGNORE.equals(handle)) {
				return list.get(0);
			} else if (MultipleResultsHandle.EXCEPTION.equals(handle)) {
				throw new RuntimeException("查询单条数据时, 返回多条数据！class:[ " + clazz + " ]");
			}
		}
		
		return null;
	}
	
	/**
	 * @description 根据属性过滤、排序查询并取Top记录
	 * @author XQF.Sui
	 * @created 2019年4月12日 下午11:01:41
	 * @param property 查询属性
	 * @param value 属性值
	 * @param sorts 排序
	 * @param num TOP记录数
	 * @return
	 */
	public List<T> selectByPropertyTopRecords(String property, Object value, Sorts sorts, int num) {
		
		Example example = new Example(clazz);
		example.createCriteria().andEqualTo(property, value);
		example.orderBy(sorts.toSqlString());
		
		RowBounds rowBounds = new RowBounds(0, num);
		
		return selectByExampleAndRowBounds(example, rowBounds);
	}
	
	/**
	 * @description 根据Example、排序查询并取Top记录
	 * @author XQF.Sui
	 * @created 2019年4月12日 下午11:04:41
	 * @param example
	 * @param sorts
	 * @param num
	 * @return
	 */
	public List<T> selectByExampleTopRecords(Example example, Sorts sorts, int num) {
		
		example.orderBy(sorts.toSqlString());
		RowBounds rowBounds = new RowBounds(0, num);
		
		return selectByExampleAndRowBounds(example, rowBounds);
	}
	
	/**
	 * @description 根据Example和RowBounds分页查询数据
	 * @author XQF.Sui
	 * @created 2019年4月11日 下午9:57:27
	 * @param example
	 * @param rowBounds
	 * @return
	 */
	public List<T> selectByExampleAndRowBounds(Example example, RowBounds rowBounds) {
		return mapper.selectByExampleAndRowBounds(example, rowBounds);
	}
	
	/**
	 * @description 根据主键查询数据
	 * @author XQF.Sui
	 * @created 2019年4月11日 下午9:57:59
	 * @param key
	 * @return
	 */
	public T selectByPrimaryKey(Object key) {
		return mapper.selectByPrimaryKey(key);
	}
	
	/**
	 * @description 根据实体对象和RowBounds分页查询数据
	 * @author XQF.Sui
	 * @created 2019年4月11日 下午9:58:28
	 * @param record
	 * @param rowBounds
	 * @return
	 */
	public List<T> selectByRowBounds(T record, RowBounds rowBounds) {
		return mapper.selectByRowBounds(record, rowBounds);
	}
	
	/**
	 * @description 根据实体对象查询符合要求的记录数(count)
	 * @author XQF.Sui
	 * @created 2019年4月11日 下午9:59:35
	 * @param record
	 * @return
	 */
	public int selectCount(T record) {
		return mapper.selectCount(record);
	}
	
	/**
	 * @description 根据Example查询符合要求的记录数(count)
	 * @author XQF.Sui
	 * @created 2019年4月11日 下午10:00:17
	 * @param example
	 * @return
	 */
	public int selectCountByExample(Example example) {
		return mapper.selectCountByExample(example);
	}
	
	/**
	 * @description 根据实体对象查询一个符合要求的记录
	 * @author XQF.Sui
	 * @created 2019年4月11日 下午10:00:53
	 * @param record
	 * @return
	 */
	public T selectOne(T record) {
		return mapper.selectOne(record);
	}
	
	/**
	 * @description 根据Example查询一条符合要求的记录
	 * @author XQF.Sui
	 * @created 2019年4月11日 下午10:01:31
	 * @param example
	 * @return
	 */
	public T selectOneByExample(Example example) {
		return mapper.selectOneByExample(example);
	}
	
	/**
	 * @description 插入数据(所有字段)
	 * @author XQF.Sui
	 * @created 2019年4月11日 下午10:02:01
	 * @param record
	 * @return
	 */
	public Object insert(T record) {
		this.mapper.insert(record);
		return record.getId();
	}
	
	/**
	 * @description 插入数据(有数据的字段)
	 * @author XQF.Sui
	 * @created 2019年4月11日 下午10:02:19
	 * @param record
	 * @return
	 */
	public Object insertSelective(T record) {
		this.mapper.insertSelective(record);
		return record.getId();
	}
	
	/**
	 * @description 根据Example更新记录(所有字段)
	 * @author XQF.Sui
	 * @created 2019年4月11日 下午10:03:04
	 * @param record
	 * @param example
	 * @return
	 */
	public int updateByExample(T record, Example example) {
		return mapper.updateByExample(record, example);
	}
	
	/**
	 * @description 根据Example更新记录(有值字段)
	 * @author XQF.Sui
	 * @created 2019年4月11日 下午10:03:33
	 * @param record
	 * @param example
	 * @return
	 */
	public int updateByExampleSelective(T record, Example example) {
		return mapper.updateByExampleSelective(record, example);
	}
	
	/**
	 * @description 根据主键更新记录(所有字段)
	 * @author XQF.Sui
	 * @created 2019年4月11日 下午10:04:15
	 * @param record
	 * @return
	 */
	public int updateByPrimaryKey(T record) {
		return mapper.updateByPrimaryKey(record);
	}
	
	/**
	 * @description 根据主键更新记录(有值字段)
	 * @author XQF.Sui
	 * @created 2019年4月11日 下午10:35:58
	 * @param record
	 * @return
	 */
	public int updateByPrimaryKeySelective(T record) {
		return mapper.updateByPrimaryKeySelective(record);
	}
	
	/**
	 * @description 根据实体对象删除数据
	 * @author XQF.Sui
	 * @created 2019年4月11日 下午10:36:31
	 * @param record
	 * @return
	 */
	public int delete(T record) {
		return mapper.delete(record);
	}
	
	/**
	 * @description 根据Example删除数据
	 * @author XQF.Sui
	 * @created 2019年4月11日 下午10:37:00
	 * @param example
	 * @return
	 */
	public int delete(Example example) {
		return mapper.deleteByExample(example);
	}
	
	/**
	 * @description 根据主键删除数据
	 * @author XQF.Sui
	 * @created 2019年4月11日 下午10:37:22
	 * @param key
	 * @return
	 */
	public int deleteByPrimaryKey(Object key) {
		return mapper.deleteByPrimaryKey(key);
	}
	
	/**
	 * @description 根据主键查询是否存在
	 * @author XQF.Sui
	 * @created 2019年4月11日 下午10:37:22
	 * @param key
	 * @return
	 */
	public boolean existsWithPrimaryKey(Object key) {
		return mapper.existsWithPrimaryKey(key);
	}
	
	/**
	 * @description: 查询多结果处理方式
	 * @author XQF.Sui
	 * @created 2019年4月11日 下午10:37:56
	 * @version 1.0
	 */
	public enum MultipleResultsHandle {
		IGNORE,			// 忽略, 返回第一条
		EXCEPTION;		// 抛出异常, 进行警告
		
		private static Set<MultipleResultsHandle> MultipleResultsHandleSet;
		
		static {
			MultipleResultsHandleSet = new HashSet<>(Arrays.asList(values()));
		}
		
		public static boolean contains(MultipleResultsHandle handle) {
			return MultipleResultsHandleSet.contains(handle);
		}
	}
}